package ru.compft.common.dao.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import ru.compft.common.dao.UserDao;
import ru.compft.common.data.AppRole;
import ru.compft.common.data.AppRoleToUser;
import ru.compft.common.data.AppUser;
import ru.compft.common.services.RolesService;
import ru.compft.common.utils.CommonUtils;
import ru.compft.common.utils.DateTimeUtils;
import ru.compft.common.utils.GlobalConstants;

import java.io.*;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * User: ASUS
 * Date: 01.06.12
 * Time: 0:06
 * Пример реализации функциональности работы с пользователями
 * Нужен для демонстрационной версии
 */
public class ExampleUserDaoImpl implements UserDao {
    private static final Logger logger = LoggerFactory.getLogger(ExampleUserDaoImpl.class);

    private String USERS_CSV = "/users.csv";
    private String ROLES2USER_CSV = "/roles2user.csv";

    private RolesService roleService;

    public void setRoleService(RolesService roleService) {
        this.roleService = roleService;
    }

    @Override
    public AppUser findUserByLogin(String userName) {
        final List<AppUser> userList = readFromFile();
        if (!CollectionUtils.isEmpty(userList)) {
            for (AppUser appUser : userList) {
                if (appUser.getLogin().equals(userName))
                    return appUser;
            }
        }
        return null;
    }

    @Override
    public AppUser findUserById(Long userId) {
        final List<AppUser> userList = readFromFile();
        if (!CollectionUtils.isEmpty(userList)) {
            for (AppUser appUser : userList) {
                if (appUser.getId().equals(userId))
                    return appUser;
            }
        }
        return null;
    }

    @Override
    public List<AppUser> getAllUsers() {
        return readFromFile();
    }

    @Override
    public List<AppUser> getUsers(int from, int count) {
        return CommonUtils.getPartOfList(from, count, readFromFile());
    }

    @Override
    public int countAllUsers() {
        return readFromFile().size();
    }

    @Override
    public AppUser update(AppUser user) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public AppUser persist(AppUser user) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Boolean delete(AppUser user) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public List<AppRoleToUser> getAllRolesToUsers() {
        return readUserRolesFromFile();
    }

    /**
     * Считываем данные из файла
     *
     * @return
     */
    private List<AppUser> readFromFile() {
        // Считываем из файла меппинг userId -> List<roleId>
        final List<AppRoleToUser> userToRoles = readUserRolesFromFile();
        final List<AppUser> result = new LinkedList<AppUser>();
        BufferedReader br = null;

        try {
            final String fullPath = System.getProperty(GlobalConstants.USER_DIR_PROP_NAME) + GlobalConstants.CACHE_DATA + USERS_CSV;
            final File resourceFile = new File(fullPath);
            if (!resourceFile.exists())
                throw new FileNotFoundException("File " + fullPath + " not found.");

            br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(resourceFile), GlobalConstants.DEFAULT_ENCODING));

            String strLine;
            boolean firstString = true;

            //Read File Line By Line
            while ((strLine = br.readLine()) != null) {
                // пропускаем первую строку, т.к. там лежат имена колонок
                if (firstString) {
                    firstString = false;
                    continue;
                }

                strLine = strLine.replaceAll(GlobalConstants.DOUBLE_QUOTA, GlobalConstants.EMPTY_STRING);

                final String[] fieldArray = strLine.split(GlobalConstants.DOT_COMMA);
                if (fieldArray.length != 10)
                    throw new Exception("Field array more or less than 10 records");

                final Long id = Long.valueOf(fieldArray[0].trim());
                final String login = fieldArray[1].trim();
                final String password = fieldArray[2].trim();
                final String firstName = fieldArray[3].trim();
                final String lastName = fieldArray[4].trim();
                final boolean enabled = GlobalConstants.Y.equals(fieldArray[5].trim());
                final boolean account_non_expired = GlobalConstants.Y.equals(fieldArray[6].trim());
                final boolean credentials_non_expired = GlobalConstants.Y.equals(fieldArray[7].trim());
                final boolean account_non_locked = GlobalConstants.Y.equals(fieldArray[8].trim());
                final Date regDate = DateTimeUtils.getStringAsDate(fieldArray[9].trim());
                final Date lastActivity = DateTimeUtils.getStringAsDate(fieldArray[10].trim());

                // создаем пользователя
                final AppUser user = new AppUser();
                user.setId(System.currentTimeMillis());
                user.setLogin(login);
                user.setPassword(password);
                user.setFirstName(firstName);
                user.setLastName(lastName);
                user.setEnabled(enabled);
                user.setAccountNonExpired(account_non_expired);
                user.setCredentialsNonExpired(credentials_non_expired);
                user.setAccountNonLocked(account_non_locked);
                user.setRegDate(regDate);
                user.setLastActivity(lastActivity);

                // добавляем ему его роли
                if (!CollectionUtils.isEmpty(userToRoles)) {
                    for (AppRoleToUser roleToUser : userToRoles) {
                        if (roleToUser.getUserId().equals(id)) {
                            final AppRole appRole = roleService.findRoleById(roleToUser.getRoleId());
                            if (appRole != null) user.addRole(appRole);
                        }
                    }
                }

                result.add(user);
            }
        } catch (IOException e) {
            logger.error("Can't read from file " + USERS_CSV, e);
        } catch (Exception e) {
            logger.error("Error while read from file " + USERS_CSV, e);
        } finally {
            if (br != null)
                try {
                    br.close();
                } catch (IOException e) {
                    // ignore
                }
        }

        return result;
    }

    /**
     * Инициализация кеша
     */
    private List<AppRoleToUser> readUserRolesFromFile() {
        final List<AppRoleToUser> userToRoles = new LinkedList<AppRoleToUser>();
        BufferedReader br = null;

        try {
            final String fullPath = System.getProperty(GlobalConstants.USER_DIR_PROP_NAME) + GlobalConstants.CACHE_DATA + ROLES2USER_CSV;
            final File resourceFile = new File(fullPath);
            if (!resourceFile.exists())
                throw new FileNotFoundException("File " + fullPath + " not found.");

            br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(resourceFile), GlobalConstants.DEFAULT_ENCODING));

            String strLine;
            boolean firstString = true;

            //Read File Line By Line
            while ((strLine = br.readLine()) != null) {
                // пропускаем первую строку, т.к. там лежат имена колонок
                if (firstString) {
                    firstString = false;
                    continue;
                }

                strLine = strLine.replaceAll(GlobalConstants.DOUBLE_QUOTA, GlobalConstants.EMPTY_STRING);

                final String[] fieldArray = strLine.split(GlobalConstants.DOT_COMMA);
                if (fieldArray.length != 2)
                    throw new Exception("Field array more or less than 2 records");

                final Long roleId = Long.valueOf(fieldArray[0].trim());
                final Long userId = Long.valueOf(fieldArray[1].trim());

                AppRoleToUser appRoleToUser = new AppRoleToUser();
                appRoleToUser.setId(System.currentTimeMillis());
                appRoleToUser.setRoleId(roleId);
                appRoleToUser.setUserId(userId);
                userToRoles.add(appRoleToUser);
            }
        } catch (IOException e) {
            logger.error("Can't read from file " + ROLES2USER_CSV, e);
        } catch (Exception e) {
            logger.error("Error while read from file " + ROLES2USER_CSV, e);
        } finally {
            if (br != null)
                try {
                    br.close();
                } catch (IOException e) {
                    // ignore
                }
        }
        return userToRoles;
    }
}
